{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# Scale Invariant Feature Transform (SIFT)",
   "id": "953ec648aef33556"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 图像尺度空间",
   "id": "9b6b563719be417a"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "在一定的范围内，无论物体是大还是小，人眼都可以分辨出来，然而计算机想要有相同的能力却很难，所以要让机器能够对物体在不同的尺度下有一个统一的认知，就需要考虑图像在不同的尺度下都存在的特点",
   "id": "f09076cb73e06d14"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "### 尺度空间的获取通常使用高斯模糊来实现\n",
    "![title](data/sift_3.png)"
   ],
   "id": "39dfbe771478ebc7"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_2.png)",
   "id": "d599cfeb389be29c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "不同的Sigma的高斯函数决定了对图像的平滑程度，越大的sigma对应的图像越模糊",
   "id": "41f1b4b928579775"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 多分辨金字塔",
   "id": "d63f88a9ea51e286"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_4.png)",
   "id": "6676442f19d0a516"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 高斯差分金字塔(DOG)",
   "id": "96d41edfd202d5fb"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_5.png)",
   "id": "c289475d2f5cc79f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_6.png)",
   "id": "e3e90ca70c95559f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### DoG空间极值检测",
   "id": "df89dc4848190ee"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "为了寻找尺度空间的极值点，每个像素点要和其图像域（同一尺度空间）和尺度域（相邻的尺度空间）的所有相邻点进行比较，当其大于（或者小于）所有相邻点时，该点就是极值点。如下图所示，中间的检测点要和其所在图像的3×3邻域8个像素点，以及其相邻的上下两层的3×3领域18个像素点，共26个像素点进行比较。\n",
   "id": "611063c564ae5950"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_7.png)",
   "id": "d10abbca0bbd1fd8"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 关键点的精确定位",
   "id": "86a867e232b929c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "这些候选关键点是DOG空间的局部极值点，而且这些极值点均为离散的点，精确定位极值点的一种方法是，对尺度空间DoG函数进行曲线拟合，计算其极值点，从而实现关键点的精确定位。",
   "id": "a4c13fc7a4726278"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_8.png)",
   "id": "130e61884ab74d54"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_9.png)",
   "id": "11cb71adbd8c5800"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 消除边界响应",
   "id": "a898e97a4c2f1bcf"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_10.png)",
   "id": "19c2671d9b157fb4"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 特征点的主方向",
   "id": "c4d3a98d8eddc721"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_11.png)",
   "id": "6b62fc44e19d4e30"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "每个特征点可以得到三个信息(x,y,σ,θ)，即位置、尺度和方向。具有多个方向的关键点可以被复制成多份，然后将方向值分别赋给复制后的特征点，一个特征点就产生了多个坐标、尺度相等，但是方向不同的特征点。",
   "id": "bfd0efec56e60efa"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 生成特征描述",
   "id": "2a6345e17e3ccb55"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "在完成关键点的梯度计算后，使用直方图统计邻域内像素的梯度和方向。",
   "id": "87c100aeff2bfe7f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_12.png)",
   "id": "1e1beacc9d95e373"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "为了保证特征矢量的旋转不变性，要以特征点为中心，在附近邻域内将坐标轴旋转θ角度，即将坐标轴旋转为特征点的主方向。",
   "id": "4232864067f4c066"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_14.png)",
   "id": "3d1ec33a34e9eb79"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "旋转之后的主方向为中心取8x8的窗口，求每个像素的梯度幅值和方向，箭头方向代表梯度方向，长度代表梯度幅值，然后利用高斯窗口对其进行加权运算，最后在每个4x4的小块上绘制8个方向的梯度直方图，计算每个梯度方向的累加值，即可形成一个种子点，即每个特征的由4个种子点组成，每个种子点有8个方向的向量信息。",
   "id": "9939ae9fd472e2ec"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_16.png)",
   "id": "2ff47be72171a6b3"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "论文中建议对每个关键点使用4x4共16个种子点来描述，这样一个关键点就会产生128维的SIFT特征向量。",
   "id": "3fafaaa3db71aea9"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "![title](data/sift_17.png)",
   "id": "5360e09174d1d815"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### opencv SIFT函数",
   "id": "52a2a8c5d712af00"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-20T17:03:44.540047Z",
     "start_time": "2025-09-20T17:03:32.833131Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "from cv2.version import opencv_version\n",
    "\n",
    "\n",
    "def cv_show(img, name='Image'):\n",
    "    cv2.imshow(name, img)\n",
    "    cv2.waitKey(0)\n",
    "    cv2.destroyAllWindows()\n",
    "\n",
    "img = cv2.imread('data/test_1.jpg')\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "cv_show(gray, 'gray')"
   ],
   "id": "2b24fe97ba80cec3",
   "outputs": [],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-20T17:08:44.796409Z",
     "start_time": "2025-09-20T17:08:44.780859Z"
    }
   },
   "cell_type": "code",
   "source": "cv2.__version__",
   "id": "2822b3cc1b347942",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'3.4.15'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 7
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-20T17:03:46.763207Z",
     "start_time": "2025-09-20T17:03:46.330130Z"
    }
   },
   "cell_type": "code",
   "source": [
    "sift = cv2.xfeatures2d.SIFT_create()\n",
    "kp = sift.detect(gray, None)"
   ],
   "id": "794260946b99ccc9",
   "outputs": [],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-20T17:04:11.687853Z",
     "start_time": "2025-09-20T17:04:07.230102Z"
    }
   },
   "cell_type": "code",
   "source": [
    "img = cv2.drawKeypoints(gray, kp, img)\n",
    "cv_show(img)"
   ],
   "id": "d4acc812cb91a4ca",
   "outputs": [],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-09-20T17:04:26.332162Z",
     "start_time": "2025-09-20T17:04:26.005134Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 计算特征\n",
    "kp, des = sift.compute(gray, kp)\n",
    "print(des.shape)"
   ],
   "id": "3eb8eaaa5f13b4e1",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(6807, 128)\n"
     ]
    }
   ],
   "execution_count": 4
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "72ff5e4d99210b85"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
